// import * as Cesium from 'cesium'
// import TileCoding from './TileCoding'


// var _rows = [ 2, 2, 11, 2, 2, 2, 3, 2, 5, 5, 3, 2, 2, 4, 8, 8, 8 ];
// var _cols = [ 2, 2, 15, 2, 3, 2, 2, 3, 5, 5, 3, 2, 2, 4, 8, 8, 8];//x


// var _rows = [ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ];
// var _cols = [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2];//x
    /**
     * A tiling scheme for geometry referenced to a simple {@link Cesium.GeographicProjection} where
     * longitude and latitude are directly mapped to X and Y.  This projection is commonly
     * known as geographic, equirectangular, equidistant cylindrical, or plate carrée.
     *
     * @alias GeographicEntiryScheme
     * @constructor
     *
     * @param {Object} [options] Object with the following properties:
     * @param {Cesium.Ellipsoid} [options.ellipsoid=Cesium.Ellipsoid.WGS84] The ellipsoid whose surface is being tiled. Defaults to
     * the WGS84 ellipsoid.
     * @param {Cesium.Rectangle} [options.rectangle=Cesium.Rectangle.MAX_VALUE] The rectangle, in radians, covered by the tiling scheme.
     * @param {Number} [options.numberOfLevelZeroTilesX=2] The number of tiles in the X direction at level zero of
     * the tile tree.
     * @param {Number} [options.numberOfLevelZeroTilesY=1] The number of tiles in the Y direction at level zero of
     * the tile tree.
     */
    function GeographicEntiryScheme(options) {
        if (!Cesium.defined(options) || !Cesium.defined(options.ROWS)||
        !Cesium.defined(options.COLS)||!Cesium.defined(options.RECTANGLE)) {
            throw new Cesium.DeveloperError('options.GridEnum is required.');
        }
        

        this._ellipsoid = Cesium.defaultValue(options.ellipsoid, Cesium.Ellipsoid.WGS84);
        this._projection = new Cesium.GeographicProjection(this._ellipsoid);
      
        var rec=options.RECTANGLE;
        
        this._rectangle=new Cesium.Rectangle(Cesium.Math.toRadians(rec[0]),Cesium.Math.toRadians(rec[1]),
            Cesium.Math.toRadians(rec[2]),Cesium.Math.toRadians(rec[3]));

        this._rows=options.ROWS;
        this._cols=options.COLS;
        this._code=options.CODE;
        this._ID=options.ID;
       // this._tileCoding=new TileCoding(options.TILECODINGURL);

        this._numberOfLevelZeroTilesX = this._cols[0];
        this._numberOfLevelZeroTilesY = this._rows[0];

    }

  
    GeographicEntiryScheme.Rows=function(){
        return function(){
            return _rows;
        }
       
    }
    GeographicEntiryScheme.Cols=function(){
        return function(){
            return _cols;
        }
    }
    
    GeographicEntiryScheme.prototype.Test=function(){
        // var cusTile=new CustomTile({
        //     x:1500,
        //     y:1200,
        //     level:7,
        //     tilingScheme:this
        // })

        // this.codeTile(cusTile)
        // console.log(cusTile);

    }


    Object.defineProperties(GeographicEntiryScheme.prototype, {
        /**
         * Gets the ellipsoid that is tiled by this tiling scheme.
         * @memberof GeographicEntiryScheme.prototype
         * @type {Cesium.Ellipsoid}
         */
        ellipsoid : {
            get : function() {
                return this._ellipsoid;
            }
        },

        /**
         * Gets the rectangle, in radians, covered by this tiling scheme.
         * @memberof GeographicEntiryScheme.prototype
         * @type {Cesium.Rectangle}
         */
        rectangle : {
            get : function() {
                return this._rectangle;
            }
        },

        /**
         * Gets the map projection used by this tiling scheme.
         * @memberof GeographicEntiryScheme.prototype
         * @type {MapProjection}
         */
        projection : {
            get : function() {
                return this._projection;
            }
        }
    });

    /**
     * Gets the total number of tiles in the X direction at a specified level-of-detail.
     *
     * @param {Number} level The level-of-detail.
     * @returns {Number} The number of tiles in the X direction at the given level.
     */
    GeographicEntiryScheme.prototype.getNumberOfXTilesAtLevel = function(level) {
        //return this._numberOfLevelZeroTilesX << level;
        var num=1;
        for(var L=0;L<=level;L++){
            num=num*this._cols[L];
        }
        return num;
    };

    /**
     * Gets the total number of tiles in the Y direction at a specified level-of-detail.
     *
     * @param {Number} level The level-of-detail.
     * @returns {Number} The number of tiles in the Y direction at the given level.
     */
    GeographicEntiryScheme.prototype.getNumberOfYTilesAtLevel = function(level) {
       // return this._numberOfLevelZeroTilesY << level;
       var num=1;
       for(var L=0;L<=level;L++){
           num=num*this._rows[L];
       }
       return num;
    };

   

    /**
     * Transforms a rectangle specified in geodetic radians to the native coordinate system
     * of this tiling scheme.
     *
     * @param {Cesium.Rectangle} rectangle The rectangle to transform.
     * @param {Cesium.Rectangle} [result] The instance to which to copy the result, or undefined if a new instance
     *        should be created.
     * @returns {Cesium.Rectangle} The specified 'result', or a new object containing the native rectangle if 'result'
     *          is undefined.
     */
    GeographicEntiryScheme.prototype.rectangleToNativeRectangle = function(rectangle, result) {
        //>>includeStart('debug', pragmas.debug);
        Cesium.Check.Cesium.defined('rectangle', rectangle);
        //>>includeEnd('debug');

        var west = Cesium.Math.toDegrees(rectangle.west);
        var south = Cesium.Math.toDegrees(rectangle.south);
        var east = Cesium.Math.toDegrees(rectangle.east);
        var north = Cesium.Math.toDegrees(rectangle.north);

        if (!Cesium.defined(result)) {
            return new Cesium.Rectangle(west, south, east, north);
        }

        result.west = west;
        result.south = south;
        result.east = east;
        result.north = north;
        return result;
    };

    /**
     * Converts tile x, y coordinates and level to a rectangle expressed in the native coordinates
     * of the tiling scheme.
     *
     * @param {Number} x The integer x coordinate of the tile.
     * @param {Number} y The integer y coordinate of the tile.
     * @param {Number} level The tile level-of-detail.  Zero is the least detailed.
     * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
     *        should be created.
     * @returns {Cesium.Rectangle} The specified 'result', or a new object containing the rectangle
     *          if 'result' is undefined.
     */
    GeographicEntiryScheme.prototype.tileXYToNativeRectangle = function(x, y, level, result) {
        var rectangleRadians = this.tileXYToRectangle(x, y, level, result);
        rectangleRadians.west = Cesium.Math.toDegrees(rectangleRadians.west);
        rectangleRadians.south = Cesium.Math.toDegrees(rectangleRadians.south);
        rectangleRadians.east = Cesium.Math.toDegrees(rectangleRadians.east);
        rectangleRadians.north = Cesium.Math.toDegrees(rectangleRadians.north);
        return rectangleRadians;
    };
    // GeographicEntiryScheme.prototype.tileXYToNativeRectangle = function(x, y, level, result) {
    //     var rectangleRadians = this.tileXYToRectangle(x, y, level, result);
       
    //      var west = Cesium.Math.toDegrees(rectangleRadians.west);
    //      var south = Cesium.Math.toDegrees(rectangleRadians.south);
    //      var east = Cesium.Math.toDegrees(rectangleRadians.east);
    //      var north = Cesium.Math.toDegrees(rectangleRadians.north);

    //      console.log(x,y,level,west,south,east,north);

       
    //     var leftDown=GeographicEntiryScheme.BLToGauss(rectangleRadians.west,rectangleRadians.south);
    //     var rightUp=GeographicEntiryScheme.BLToGauss(rectangleRadians.east,rectangleRadians.north);

    //     rectangleRadians.west = (leftDown[0]);
    //     rectangleRadians.south = (leftDown[1]);
    //     rectangleRadians.east = (rightUp[0]);
    //     rectangleRadians.north = (rightUp[1]);
        
    //     console.log(leftDown[0],leftDown[1],rightUp[0],rightUp[1])

    //     return rectangleRadians;
    // };

    /**
     * Converts tile x, y coordinates and level to a cartographic rectangle in radians.
     *
     * @param {Number} x The integer x coordinate of the tile.
     * @param {Number} y The integer y coordinate of the tile.
     * @param {Number} level The tile level-of-detail.  Zero is the least detailed.
     * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
     *        should be created.
     * @returns {Cesium.Rectangle} The specified 'result', or a new object containing the rectangle
     *          if 'result' is undefined.
     */
    GeographicEntiryScheme.prototype.tileXYToRectangle = function(x, y, level, result) {
        var rectangle = this._rectangle;

        var xTiles = this.getNumberOfXTilesAtLevel(level);
        var yTiles = this.getNumberOfYTilesAtLevel(level);

        var xTileWidth = rectangle.width / xTiles;
        var west = x * xTileWidth + rectangle.west;
        var east = (x + 1) * xTileWidth + rectangle.west;

        var yTileHeight = rectangle.height / yTiles;
        var north = rectangle.north - y * yTileHeight;
        var south = rectangle.north - (y + 1) * yTileHeight;

        if (!Cesium.defined(result)) {
            result = new Cesium.Rectangle(west, south, east, north);
        }

        result.west = west;
        result.south = south;
        result.east = east;
        result.north = north;
        return result;
    };

    /**
     * Calculates the tile x, y coordinates of the tile containing
     * a given cartographic position.
     *
     * @param {Cesium.Cartographic} position The position.
     * @param {Number} level The tile level-of-detail.  Zero is the least detailed.
     * @param {Cesium.Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance
     *        should be created.
     * @returns {Cesium.Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates
     *          if 'result' is undefined.
     */
    GeographicEntiryScheme.prototype.positionToTileXY = function(position, level, result) {
        var rectangle = this._rectangle;
        if (!Cesium.Rectangle.contains(rectangle, position)) {
            // outside the bounds of the tiling scheme
            return undefined;
        }

        var xTiles = this.getNumberOfXTilesAtLevel(level);
        var yTiles = this.getNumberOfYTilesAtLevel(level);

        var xTileWidth = rectangle.width / xTiles;
        var yTileHeight = rectangle.height / yTiles;

        var longitude = position.longitude;
        if (rectangle.east < rectangle.west) {
            longitude += Cesium.Math.TWO_PI;
        }

        var xTileCoordinate = (longitude - rectangle.west) / xTileWidth | 0;
        if (xTileCoordinate >= xTiles) {
            xTileCoordinate = xTiles - 1;
        }

        var yTileCoordinate = (rectangle.north - position.latitude) / yTileHeight | 0;
        if (yTileCoordinate >= yTiles) {
            yTileCoordinate = yTiles - 1;
        }

        if (!Cesium.defined(result)) {
            return new Cesium.Cartesian2(xTileCoordinate, yTileCoordinate);
        }

        result.x = xTileCoordinate;
        result.y = yTileCoordinate;
        return result;
    };
    /**
     * 
    * @param {Number} x The integer x coordinate of the tile.
     * @param {Number} y The integer y coordinate of the tile.
     * @param {Number} level The tile level-of-detail.  Zero is the least detailed.
     * @returns {array} result The children of current tile
     */
    GeographicEntiryScheme.prototype.Children=function(x,y,level,result){
        if(level>=this._rows.length)return [];
        var leftUpX=x*this._cols[level+1];
        var leftUpY=y*this._rows[level+1];
        if(!Cesium.defined(result))result=[];
        for(var row=0;row<this._rows[level+1];row++){
            for(var col=0;col<this._cols[level+1];col++){
                result.push(leftUpX+col,leftUpY+row);
            }
        }
        return result;
    }

 /**
     * 
    * @param {Number} x The integer x coordinate of the tile.
     * @param {Number} y The integer y coordinate of the tile.
     * @param {Number} level The tile level-of-detail.  Zero is the least detailed.
     * @returns {Cesium.Cartesian2} result The parent of current tile
     */
    GeographicEntiryScheme.prototype.Parent=function(x,y,level,result){
        if(level<=0 )return undefined;
        var pX=Math.floor(x/this._cols[level]);
        var pY=Math.floor(y/this._rows[level]);
        if(!Cesium.defined(result))result=new Cesium.Cartesian2();
        result.x=pX;
        result.y=pY;
        return result;
    }

    GeographicEntiryScheme.BLToGauss=function( longitude,  latitude) {
        
        longitude=Cesium.Math.toDegrees(longitude);
        latitude=Cesium.Math.toDegrees(latitude);
        
        var ProjNo = 0;
        var ZoneWide; // //带宽
        var output = [];
        var longitude1, latitude1, longitude0, X0, Y0, xval, yval;
        var a, f, e2, ee, NN, T, C, A, M, iPI;
        iPI = 0.0174532925199433; // //3.1415926535898/180.0;
        ZoneWide = 3; // //6度带宽
        a = 6378245.0;
        f = 1.0 / 298.3; // 54年北京坐标系参数
        // //a=6378140.0; f=1/298.257; //80年西安坐标系参数
        ProjNo =  Math.floor(longitude / ZoneWide);
        longitude0 = ProjNo * ZoneWide + ZoneWide / 2;
        longitude0 = longitude0 * iPI;
        longitude1 = longitude * iPI; // 经度转换为弧度
        latitude1 = latitude * iPI; // 纬度转换为弧度
        e2 = 2 * f - f * f;
        ee = e2 / (1.0 - e2);
        NN = a
          / Math.sqrt(1.0 - e2 * Math.sin(latitude1)
            * Math.sin(latitude1));
        T = Math.tan(latitude1) * Math.tan(latitude1);
      C = ee * Math.cos(latitude1) * Math.cos(latitude1);
        A = (longitude1 - longitude0) * Math.cos(latitude1);
        M = a
          * ((1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256)
            * latitude1
            - (3 * e2 / 8 + 3 * e2 * e2 / 32 + 45 * e2 * e2 * e2
              / 1024) * Math.sin(2 * latitude1)
            + (15 * e2 * e2 / 256 + 45 * e2 * e2 * e2 / 1024)
            * Math.sin(4 * latitude1) - (35 * e2 * e2 * e2 / 3072)
            * Math.sin(6 * latitude1));
        // 因为是以赤道为Y轴的，与我们南北为Y轴是相反的，所以xy与高斯投影的标准xy正好相反;
        xval = NN
          * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 14
            * C - 58 * ee)
            * A * A * A * A * A / 120);
        yval = M
          + NN
          * Math.tan(latitude1)
          * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61
            - 58 * T + T * T + 270 * C - 330 * ee)       * A * A * A * A * A * A / 720); 
            //  X0 = 1000000 * (ProjNo + 1) + 500000;  
              X0 =  500000; 
               Y0 = 0;   xval = xval + X0; 
                 yval = yval + Y0;  
                  output[0] = xval;   
                  output[1] = yval;  
                   return output; 
                 };


             
                 
                 GeographicEntiryScheme.prototype.codeTile=function( tile)
                 {
                     if(Cesium.defined(tile._codeStr))return;
                    
                     var L=tile._level;
                 
                     var codeType =this._code[L];
                    
                     
                     var colCount = this._cols[L];
                     var rowCount=this._rows[L];
                     var curCode;
                     if(L==0){
                         if(tile.y==0)
                             curCode="N";
                         else if(tile.y==1)
                             curCode="S";
                         if(colCount==2){
                             if(tile.x==1){
                                 curCode=curCode+"E";
                 
                             }
                             else{
                                 curCode+="W";
                             }
                         }
                 
                         tile._codeStr=curCode;
                         return;
                     }
                 
                 
                     
                     if(!Cesium.defined(tile._region)){
                        tile._region= this.regionOfTile(tile);
                   
                     }




                     var region=tile._region;
                     var irow;
                     var icol;
                     var ilocalX;
                     var ilocalY;
                     if(!Cesium.defined(tile.parent)){
                        ilocalX=tile.parentXY.x*colCount;
                        ilocalY=tile.parentXY.y*rowCount;
                     }
                     else{
                        ilocalX=tile.parent.x*colCount;
                        ilocalY=tile.parent.y*rowCount;
                     }
                     
                     irow=tile.y-ilocalY;
                     icol=tile.x-ilocalX;
                    
                   
                     var result=adustRowCol(irow,icol,rowCount,colCount,region,this,L);
                     irow=result.irow;
                     icol=result.icol;
                    
                     if (codeType === 0)
                     {
                         curCode=  zigzagCode(irow, icol, colCount);
                     }
                     else
                     {
                         curCode= xyCode(irow, icol,L,this._ID);
                     }
                     tile._codeStr=tile.parent._codeStr+curCode;
                    //  if(test(tile,119.883490929,32.45006332967)){
                    //      console.log(tile._codeStr);
                    //      var lon1=Cesium.Math.toDegrees(tile.rectangle.west);
                    //      var lon2=Cesium.Math.toDegrees(tile.rectangle.east);
                    //      var lat1=Cesium.Math.toDegrees(tile.rectangle.south);
                    //      var lat2=Cesium.Math.toDegrees(tile.rectangle.north);
                    //      console.log(lon1,lon2,lat1,lat2);
                    //  }
                 }
                 function test(tile,lon,lat){
                     var rec=tile.rectangle;
                     lon=Cesium.Math.toRadians(lon);
                     lat=Cesium.Math.toRadians(lat);
                     if(rec.east>lon && rec.west<lon && rec.north>lat && rec.south<lat){
                         return true;
                     }
                     return false;
                 }

                 function adustRowCol(irow,icol,rowCount,colCount,region,tilingScheme,level){
                   
                    if(tilingScheme._ID==="BEIDOUGRID" && level==1){
                        if(region==="NW" || region==="NE"){
                            irow=rowCount-1-irow;
                        }
                  
                        icol=icol+1;
                    }
                    else{
                        if(region==="NE" || !Cesium.defined(region)){
                            irow=rowCount-1-irow;
                        }
                        else if(region==="NW"){
                            irow=rowCount-1-irow;
                            icol=colCount-1-icol;
                        }
                        else if(region==="SW"){
                            icol=colCount-1-icol;
                        }
                    }

                  
                    var result={};
                    result.irow=irow;
                    result.icol=icol;
                    return result;

                 }
                 
                 GeographicEntiryScheme.prototype.regionOfTile=function(tile){
                     var center=Cesium.Rectangle.center(tile._rectangle);
                     var lon=center.longitude;
                     var lat=center.latitude;
                     if(lon>0 && lon<Math.PI && lat>0 && lat<Math.PI/2)
                     return "NE";
                     if(lon>-Math.PI && lon<0 && lat>0 && lat<Math.PI/2)
                     return "NW";
                     if(lon>-Math.PI && lon<0 && lat<0 && lat>-Math.PI/2)
                     return "SW";
                     if(lon>0 && lon<Math.PI && lat<0 && lat>-Math.PI/2)
                     return "SE";
                 
                     return undefined;
                 }
                 
                 function zigzagCode(iRow, iCol,colCount)
                 {
                     var num = iRow * colCount + iCol;
                     return num.toString();
                 }
                 function xyCode( irow, icol, Level,id)
                 {
                     
                     var colStr 
                     var rowStr;
                     var twoBitCodeLevel=1;//beidou
                     if(id==="GEOENTITYGRID")//地理实体
                        twoBitCodeLevel=2;
                     
                     if (Level != twoBitCodeLevel)
                     {
                          rowStr = irow.toString(16).toUpperCase();//16进制
                          colStr= icol.toString(16).toUpperCase();;
                        
                     }
                     else
                     {
                         var aStr='A'.charCodeAt();
                         aStr += irow;
                         rowStr=String.fromCharCode(aStr);
                        
                         colStr=icol.toString().padStart(2,"0");
                     }
                     return colStr + rowStr;
                 }




 export default GeographicEntiryScheme;
